﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Mime;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using RoadPlot;

//http://www.charlespetzold.com/blog/2008/01/Mathematics-of-ArcSegment.html
namespace RoadPlotUITest
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        Point[] _l1 = new Point[] { new Point(10, 10), new Point(400, 400) };
        Point[] _l2 = new Point[] { new Point(400, 10), new Point(10, 400) };

        Point[] _active;

        bool _bMoving = false;

        List<Point> _curve1 = new List<Point> { new Point(100, 100), new Point(200, 100), new Point(300, 200), new Point(300, 300) };
        List<Point> _curve2 = new List<Point> { new Point(100, 100), new Point(200, 100), new Point(300, 200), new Point(300, 300) };
        List<Point> _curve3 = new List<Point> { new Point(100, 100), new Point(200, 100), new Point(300, 200), new Point(300, 300) };


        int _activeIndex;

        public MainWindow()
        {
            InitializeComponent();
            DrawLines();

            canvas1.MouseDown += new MouseButtonEventHandler(md);
            canvas1.MouseMove += new MouseEventHandler(mm);
            canvas1.MouseUp += new MouseButtonEventHandler(mu);

            _curve1.Add(new Point(400, 400));
            _curve1.Add(new Point(400, 500));
            _curve1.Add(new Point(400, 400));
            _curve1.Add(new Point(400, 500));

            _curve2.Add(new Point(400, 400));
            _curve2.Add(new Point(400, 500));
            _curve2.Add(new Point(400, 400));
            _curve2.Add(new Point(400, 500));
        }

        private void textBoxLine1Width_TextChanged(object sender, TextChangedEventArgs e)
        {
            DrawLines();
        }

        private void textBoxLine2Width_TextChanged(object sender, TextChangedEventArgs e)
        {
            DrawLines();
        }
    

        private void DrawGrabHandles(List<Point> curve)
        {
            try
            {
                for (int x = 0; x < curve.Count; x++)
                {
                    DrawPoint1(new SolidColorBrush(Color.FromRgb(130, 50, 60)), x, curve);
                }
            }
            catch (Exception)
            {
            }
        }

        
        private void DrawLines()
        {
            try
            {
                canvas1.Children.Clear();
                DrawFill();
                double baseLineTrim = double.Parse(textBox1Angle.Text);

                List<RoadRoute> routes = new List<RoadRoute>();
                routes.Add(new RoadRoute(_curve1, RoadLegend.RoadLengendFactory("A Road with a long name", 40), 30, baseLineTrim, 40));
                routes.Add(new RoadRoute(_curve2, RoadLegend.RoadLengendFactory("A Big Road", 40 ), 30, baseLineTrim, 40));
                routes.Add(new RoadRoute(_curve3, RoadLegend.RoadLengendFactory("ບຸນຍັງ ວໍລະຈິດ", 40), 30, baseLineTrim, 40));
                Road.DrawBorderedRoutes(routes, canvas1, true);
                DrawGrabHandles(_curve1);
                DrawGrabHandles(_curve2);
                DrawGrabHandles(_curve3);
            }
            catch (Exception)
            {

            }

            return;
            try
            {

                double line1width = double.Parse(textBoxLine1Width.Text);
                DrawLine(line1width, new SolidColorBrush(Color.FromRgb(0, 20, 40)), _l1);
                DrawLine(double.Parse(textBoxLine2Width.Text), new SolidColorBrush(Color.FromRgb(10, 50, 60)), _l2);

                Point ptCross = new Point();
                if (DoesIntersect(ref ptCross))
                {
                    if (DoCross(ptCross))
                    {
                        DrawPoint(new SolidColorBrush(Color.FromRgb(255, 20, 40)), ptCross);

                    }
                    PlotIntercept(ptCross);
                    // PlotGreen(ptCross, line1width);
                }

                // DrawArc(line1width);
            }
            catch (Exception)
            {

            }

        }

    

        private void PlotGreen(Point ptCross, double lineWidth)
        {
            Point[] g = new Point[4];

            PlotGreen1(ptCross, lineWidth, _l1, ref g[0], ref g[1]);
            PlotGreen1(ptCross, lineWidth, _l2, ref g[2], ref g[3]);

            // DrawArc1(lineWidth, g[0], g[2]);
        }

        private void PlotGreen1(Point ptCross, double lineWidth, Point[] pa, ref Point g1, ref Point g2)
        {
            double dx = pa[0].X - pa[1].X;
            double dy = pa[0].Y - pa[1].Y;
            double slope = dy / dx;

            double a = Math.Atan(slope);

            g1 = new Point(ptCross.X - lineWidth * Math.Cos(a), ptCross.Y - lineWidth * Math.Sin(a));

            DrawPoint(new SolidColorBrush(Color.FromRgb(100, 255, 100)), g1);

            g2 = new Point(ptCross.X + lineWidth * Math.Cos(a), ptCross.Y + lineWidth * Math.Sin(a));

            DrawPoint(new SolidColorBrush(Color.FromRgb(100, 255, 100)), g2);
        }

        private void DrawArc(double line1width)
        {
            double s = double.Parse(textBox1Angle.Text);
            PathFigure myPathFigure = new PathFigure();
            myPathFigure.StartPoint = _l2[0];

            myPathFigure.Segments.Add(
                new ArcSegment(
                    _l1[0],
                    new Size(s, s),
                    0,
                    false, /* IsLargeArc */
                    SweepDirection.Clockwise,
                    true /* IsStroked */ ));

            PathGeometry myPathGeometry = new PathGeometry();
            myPathGeometry.Figures.Add(myPathFigure);

            // Display the PathGeometry. 
            Path myPath = new Path();
            myPath.Stroke = Brushes.Red;
            myPath.StrokeThickness = line1width;
            myPath.Data = myPathGeometry;

            myPath.MouseUp += new MouseButtonEventHandler(mu);
            canvas1.Children.Add(myPath);

        }

        private void PlotIntercept(Point mid)
        {
            Point[] p1 = new Point[4];
            PlotIntercept2(2, 2, false, ref p1);

            Point[] p2 = new Point[4];

            PlotIntercept2(1, 2, true, ref p2);

            Point[] p3 = new Point[4];
            PlotIntercept2(2, 1, false, ref p3);

            //  Point[] p4 = new Point[4];
            //PlotIntercept2(1, 1, false, ref p4);

            double line1Width = double.Parse(textBoxLine1Width.Text);

            DrawArc1(line1Width, p3[0], p2[0], p1[0], false, false, mid);

            // DrawArc1(line1Width, p2[1], p3[1], p1[1], true, false, mid);

            // DrawArc1(line1Width, p2[2], p3[2], p1[2], true);

            // DrawArc1(line1Width, p2[3], p3[3], p1[3], true);
        }


        private void DrawArc1(double linewidth, Point cross1, Point cross2, Point ss, bool flipx, bool flipy, Point mid)
        {
            bool flip = false;

            if ((mid.X > ss.X) && flipx)
            {
                flip = true;
            }



            double distance0 = GetDistance(cross1, cross2);
            double s = double.Parse(textBox1Angle.Text);
            PathFigure myPathFigure = new PathFigure();
            myPathFigure.StartPoint = cross1;

            myPathFigure.Segments.Add(
                new ArcSegment(
                    cross2,
                    new Size(distance0, distance0),
                    0,
                    false, /* IsLargeArc */
                    flip ? SweepDirection.Clockwise : SweepDirection.Counterclockwise,
                    false /* IsStroked */ ));



            myPathFigure.Segments.Add(new LineSegment(ss, true /* IsStroked */ ));

            PathGeometry myPathGeometry = new PathGeometry();
            myPathGeometry.Figures.Add(myPathFigure);

            // Display the PathGeometry. 
            Path myPath = new Path();
            myPath.Fill = Brushes.Red;
            //myPath.StrokeThickness = 1;
            myPath.Data = myPathGeometry;

            myPath.MouseUp += new MouseButtonEventHandler(mu);
            canvas1.Children.Add(myPath);

        }


        private void PlotIntercept2(double scale1, double scale2, bool drawArc, ref Point[] p)
        {
            double line1Width = double.Parse(textBoxLine1Width.Text);
            double line2Width = double.Parse(textBoxLine2Width.Text);

            Point[] narrowLineIntercepts1 = new Point[2];
            Point[] narrowLineIntercepts2 = new Point[2];
            Point[] wideLineIntercepts1 = new Point[2];
            Point[] wideLineIntercepts2 = new Point[2];
            if (line1Width < line2Width)
            {
                PlotInterceptPoint(_l1, line1Width / scale1, ref narrowLineIntercepts1, ref narrowLineIntercepts2);
                PlotInterceptPoint(_l2, line2Width / scale2, ref wideLineIntercepts1, ref wideLineIntercepts2);
            }
            else
            {
                PlotInterceptPoint(_l2, line1Width / scale2, ref narrowLineIntercepts1, ref narrowLineIntercepts2);
                PlotInterceptPoint(_l1, line2Width / scale1, ref wideLineIntercepts1, ref wideLineIntercepts2);
            }

            p[0] = new Point();
            if (DoesIntersect(ref p[0], narrowLineIntercepts1, wideLineIntercepts1))
            {
                DrawPoint(new SolidColorBrush(Color.FromRgb(255, 255, 40)), p[0]);
            }

            p[1] = new Point();
            if (DoesIntersect(ref p[1], narrowLineIntercepts2, wideLineIntercepts1))
            {
                DrawPoint(new SolidColorBrush(Color.FromRgb(255, 255, 40)), p[1]);
            }

            p[2] = new Point();
            if (DoesIntersect(ref p[2], narrowLineIntercepts1, wideLineIntercepts2))
            {
                DrawPoint(new SolidColorBrush(Color.FromRgb(255, 255, 40)), p[2]);
            }

            p[3] = new Point();
            if (DoesIntersect(ref p[3], narrowLineIntercepts2, wideLineIntercepts2))
            {
                DrawPoint(new SolidColorBrush(Color.FromRgb(255, 255, 40)), p[3]);
            }

            Point mid12 = new Point();
            DrawMid(new SolidColorBrush(Color.FromRgb(255, 240, 240)), p[0], p[1], ref mid12);
            Point mid13 = new Point();
            DrawMid(new SolidColorBrush(Color.FromRgb(255, 240, 240)), p[0], p[2], ref mid13);
            Point mid24 = new Point();
            DrawMid(new SolidColorBrush(Color.FromRgb(255, 240, 240)), p[1], p[3], ref mid24);
            Point mid34 = new Point();
            DrawMid(new SolidColorBrush(Color.FromRgb(255, 240, 240)), p[2], p[3], ref mid34);



        }

        private void DrawMid(SolidColorBrush solidColorBrush, Point cross1, Point cross2, ref Point ptMid)
        {
            ptMid = new Point((cross1.X + cross2.X) / 2, (cross1.Y + cross2.Y) / 2);
            DrawPoint(solidColorBrush, ptMid);
        }

        private void PlotInterceptPoint(Point[] l, double lineWidth, ref Point[] i1, ref Point[] i2)
        {
            double dx = l[0].X - l[1].X;
            double dy = l[0].Y - l[1].Y;
            double slope = dy / dx;

            double a = Math.Atan(slope);

            i1[0] = new Point(l[0].X - lineWidth * Math.Sin(a), l[0].Y + lineWidth * Math.Cos(a));

            DrawPoint(new SolidColorBrush(Color.FromRgb(100, 200, 255)), i1[0]);

            i1[1] = new Point(l[1].X - lineWidth * Math.Sin(a), l[1].Y + lineWidth * Math.Cos(a));

            DrawPoint(new SolidColorBrush(Color.FromRgb(100, 200, 255)), i1[1]);

            i2[0] = new Point(l[0].X + lineWidth * Math.Sin(a), l[0].Y - lineWidth * Math.Cos(a));

            DrawPoint(new SolidColorBrush(Color.FromRgb(100, 200, 255)), i2[0]);

            i2[1] = new Point(l[1].X + lineWidth * Math.Sin(a), l[1].Y - lineWidth * Math.Cos(a));

            DrawPoint(new SolidColorBrush(Color.FromRgb(100, 200, 255)), i2[1]);
        }

        private bool DoCross(Point ptCross)
        {
            if (ptCross.X < Math.Min(_l1[0].X, _l1[1].X))
                return false;

            if (ptCross.X < Math.Min(_l2[0].X, _l2[1].X))
                return false;

            if (ptCross.X > Math.Max(_l1[0].X, _l1[1].X))
                return false;

            if (ptCross.X > Math.Max(_l2[0].X, _l2[1].X))
                return false;

            if (ptCross.Y < Math.Min(_l1[0].Y, _l1[1].Y))
                return false;

            if (ptCross.Y < Math.Min(_l2[0].Y, _l2[1].Y))
                return false;

            if (ptCross.Y > Math.Max(_l1[0].Y, _l1[1].Y))
                return false;

            if (ptCross.Y > Math.Max(_l2[0].Y, _l2[1].Y))
                return false;

            return true;
        }


        private void DrawPoint1(SolidColorBrush solidColorBrush, int i, List<Point> curve)
        {

            Point ptCross = curve[i];
            var polly = new Polyline
            {
                StrokeThickness = 1,
                Fill = solidColorBrush,
                Points = new PointCollection(),
                StrokeStartLineCap = PenLineCap.Round,
                StrokeEndLineCap = PenLineCap.Round,
                StrokeLineJoin = PenLineJoin.Round
            };

            //  polly.MouseDown += new MouseButtonEventHandler(md);
            polly.MouseMove += new MouseEventHandler(mm);
            polly.MouseUp += new MouseButtonEventHandler(mu);
            polly.MouseDown += new MouseButtonEventHandler(md);

            polly.Tag = new curvy(i, curve);

            polly.Points.Add(new Point(ptCross.X + 15, ptCross.Y + 15));
            polly.Points.Add(new Point(ptCross.X - 15, ptCross.Y + 15));
            polly.Points.Add(new Point(ptCross.X - 15, ptCross.Y - 15));
            polly.Points.Add(new Point(ptCross.X + 15, ptCross.Y - 15));

            if (polly.Points.Count != 0)
                canvas1.Children.Add(polly);
        }

        private void DrawPoint(SolidColorBrush solidColorBrush, Point ptCross)
        {
            Rectangle r = new Rectangle();
            r.Fill = solidColorBrush;
            r.Width = 4;
            r.Height = 4;

            r.Tag = ptCross;

            Canvas.SetLeft(r, ptCross.X - 2);
            Canvas.SetTop(r, ptCross.Y - 2);

            canvas1.Children.Add(r);
        }


        private void DrawFill()
        {
            SolidColorBrush br = new SolidColorBrush(Color.FromRgb(200, 200, 160));
            var polly = new Polyline
            {
                StrokeThickness = 1,
                Fill = br,
                Points = new PointCollection(),
                StrokeStartLineCap = PenLineCap.Round,
                StrokeEndLineCap = PenLineCap.Round,
                StrokeLineJoin = PenLineJoin.Round
            };

            //  polly.MouseDown += new MouseButtonEventHandler(md);
            polly.MouseMove += new MouseEventHandler(mm);
            polly.MouseUp += new MouseButtonEventHandler(mu);


            polly.Points.Add(new Point(0, 0));

            polly.Points.Add(new Point(1000, 0));
            polly.Points.Add(new Point(1000, 1000));
            polly.Points.Add(new Point(0, 10000));

            if (polly.Points.Count != 0)
                canvas1.Children.Add(polly);
        }

        private void DrawLine(double size, SolidColorBrush br, Point[] l)
        {
            var polly = new Polyline
            {
                StrokeThickness = size,
                Stroke = br,
                Points = new PointCollection(),
                StrokeStartLineCap = PenLineCap.Round,
                StrokeEndLineCap = PenLineCap.Round,
                StrokeLineJoin = PenLineJoin.Round
            };

            polly.MouseDown += new MouseButtonEventHandler(md);
            polly.MouseMove += new MouseEventHandler(mm);
            polly.MouseUp += new MouseButtonEventHandler(mu);

            polly.Tag = l;

            polly.Points.Add(l[0]);
            polly.Points.Add(l[1]);

            if (polly.Points.Count != 0)
                canvas1.Children.Add(polly);
        }

        void md(object o, MouseEventArgs e)
        {
            Polyline r = o as Polyline;
            if (r != null)
            {
                curvy c = (curvy)r.Tag;
                c._curve[c._index] = e.GetPosition(canvas1);

                DrawLines();
                _bMoving = true;
                return;
            }

            Polyline p = o as Polyline;
            if (p == null)
                return;
            _active = (Point[])p.Tag;

            double distance0 = GetDistance(e.GetPosition(canvas1), _active[0]);
            double distance1 = GetDistance(e.GetPosition(canvas1), _active[1]);

            if (distance0 < distance1)
            {
                _activeIndex = 0;
            }
            else
            {
                _activeIndex = 1;
            }


            _active[_activeIndex] = e.GetPosition(canvas1);
            DrawLines();
        }

        private double GetDistance(Point p1, Point p2)
        {
            double dx = p1.X - p2.X;
            double dy = p1.Y - p2.Y;
            return Math.Sqrt(dx * dx + dy * dy);
        }

        void mu(object o, MouseEventArgs e)
        {
            _bMoving = false;
            _active = null;
        }

        void mm(object o, MouseEventArgs e)
        {

            if (!_bMoving)
                return;
            // if (_active == null)
            //   return;

            Polyline r = o as Polyline;
            if (r != null)
            {
                if (r.Tag == null)
                    return;
                curvy c = (curvy)r.Tag;
                c._curve[c._index] = e.GetPosition(canvas1);
                DrawLines();
                return;
            }

            // _active[_activeIndex] = e.GetPosition(canvas1);
            DrawLines();
        }

        bool DoesIntersect(ref Point ptCross)
        {
            return DoesIntersect(ref ptCross, _l1, _l2);
        }

        static bool DoesIntersect(ref Point ptCross, Point[] l1, Point[] l2)
        {
            double x12 = l1[0].X - l1[1].X;
            double x34 = l2[0].X - l2[1].X;
            double y12 = l1[0].Y - l1[1].Y;
            double y34 = l2[0].Y - l2[1].Y;

            double c = x12 * y34 - y12 * x34;

            if (Math.Abs(c) <= 0)
            {
                // No intersection
                return false;
            }

            // Intersection
            double a = l1[0].X * l1[1].Y - l1[0].Y * l1[1].X;
            double b = l2[0].X * l2[1].Y - l2[0].Y * l2[1].X;

            ptCross.X = (a * x34 - b * x12) / c;
            ptCross.Y = (a * y34 - b * y12) / c;

            return true;
        }

        private void textBox1Angle_TextChanged(object sender, TextChangedEventArgs e)
        {
            DrawLines();
        }

        /*

          void Update()
         {
             UpdateText();
             //if (Text == null || TextPath == null || _layoutPanel == null || !_layoutHasValidSize)
               //  return;
 
             List<Point> intersectionPoints;
 
             intersectionPoints = GeometryHelper.GetIntersectionPoints(TextPath.GetFlattenedPathGeometry(), _segmentLengths);
 
             canvas1.Children.Clear();

             canvas1.Margin = new Thickness(FontSize);
 
             for (int i = 0; i < intersectionPoints.Count - 1; i++)
             {
                 double oppositeLen = Math.Sqrt(Math.Pow(intersectionPoints[i].X + _segmentLengths[i] - intersectionPoints[i + 1].X, 2.0) + Math.Pow(intersectionPoints[i].Y - intersectionPoints[i + 1].Y, 2.0)) / 2.0;
                 double hypLen = Math.Sqrt(Math.Pow(intersectionPoints[i].X - intersectionPoints[i + 1].X, 2.0) + Math.Pow(intersectionPoints[i].Y - intersectionPoints[i + 1].Y, 2.0));
 
                 double ratio = oppositeLen / hypLen;
 
                 if (ratio > 1.0)
                     ratio = 1.0;
                 else if (ratio < -1.0)
                     ratio = -1.0;
 
                 //double angle = 0.0;
 
                 double angle = 2.0 * Math.Asin(ratio) * 180.0 / Math.PI;
 
                 // adjust sign on angle
                 if ((intersectionPoints[i].X + _segmentLengths[i]) > intersectionPoints[i].X)
                 {
                     if (intersectionPoints[i + 1].Y < intersectionPoints[i].Y)
                         angle = -angle;
                 }
                 else
                 {
                     if (intersectionPoints[i + 1].Y > intersectionPoints[i].Y)
                         angle = -angle;
                 }
 
                 TextBlock currTextBlock = _textBlocks[i];
 
                 RotateTransform rotate = new RotateTransform(angle);
                 TranslateTransform translate = new TranslateTransform(intersectionPoints[i].X, intersectionPoints[i].Y - currTextBlock.DesiredSize.Height);
                 TransformGroup transformGrp = new TransformGroup();
                 transformGrp.Children.Add(rotate);
                 transformGrp.Children.Add(translate);
                 currTextBlock.RenderTransform = transformGrp;

                 canvas1.Children.Add(currTextBlock);
 
                // if (DrawLinePath == true)
                 {
                     Line line = new Line();
                     line.X1 = intersectionPoints[i].X;
                     line.Y1 = intersectionPoints[i].Y;
                     line.X2 = intersectionPoints[i + 1].X;
                     line.Y2 = intersectionPoints[i + 1].Y;
                     line.Stroke = Brushes.Black;
                     canvas1.Children.Add(line);
                 }
             }
 
             // don't draw path if already drawing line path
            // if (DrawPath == true && DrawLinePath == false)
             {
                 Path path = new Path();
                 path.Data = TextPath;
                 path.Stroke = Brushes.Black;
                 canvas1.Children.Add(path);
             }
         }

        */


    }


    public class curvy
    {
        public curvy(int index, List<Point> c)
        {
            _curve = c;
            _index = index;
        }

        public int _index;
        public List<Point> _curve;
    }

    //http://www.codeproject.com/KB/graphics/BezierSpline.aspx


}
